package com.yy.main.app.service.impl;

import com.alipay.api.AlipayApiException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xiaoleilu.hutool.json.JSONArray;
import com.xiaoleilu.hutool.json.JSONObject;
import com.yy.kit.collections.YYListKits;
import com.yy.kit.collections.YYMapKits;
import com.yy.kit.log.YYLogKits;
import com.yy.kit.string.YYStrKits;
import com.yy.kit.zfb.dto.AlipayMenuDTO;
import com.yy.kit.zfb.menu.YYAlipayMenuKits;
import com.yy.main.app.mapper.TMenuMapper;
import com.yy.main.app.mapper.TMenuMessageMapper;
import com.yy.main.app.mapper.TMessageMapper;
import com.yy.main.app.service.IMenuService;
import com.yy.pojo.base.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.*;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 杨阳
 * @since 2017-09-20
 */
@Service("iMenuService")
public class MenuServiceImpl implements IMenuService {

    @Autowired
    private TMessageMapper tMessageMapper;
    @Autowired
    private TMenuMapper tMenuMapper;
    @Autowired
    private TMenuMessageMapper tMenuMessageMapper;

    @Override
    public PageInfo selectMessageByMenuId(Integer page, Integer limit, String menuid) {
        PageHelper.startPage(page, limit);
        List<TMessage> msgList = tMessageMapper.selectMessageByMenuId(menuid);
        return new PageInfo(msgList);
    }

    @Override
    public List<TMessage> selectMessageByMenuId(String menuid) {
        return tMessageMapper.selectMessageByMenuId(menuid);
    }

    @Override
    @Transactional
    public Map<String, Object> delMenu(String id) {
        Map<String, Object> map = YYMapKits.createHashMap();
        Integer b = tMenuMapper.deleteByPrimaryKey(id);
        if (b > 0) {
            // 删除关键字后，再删除与消息关联表中的数据
            TMenuMessageExample example = new TMenuMessageExample();
            example.createCriteria().andMenu_idEqualTo(id);
            tMenuMessageMapper.deleteByExample(example);

            map.put("success", Boolean.TRUE);
            map.put("msg", "删除成功!");
            return map;
        } else {
            map.put("success", Boolean.FALSE);
            map.put("msg", "删除失败，请重试!");
            return map;
        }
    }

    @Override
    @Transactional
    public Map<String, Object> saveMenu(TMenu menu, String msgid) {
        Map<String, Object> result = YYMapKits.createHashMap();
        if (1 == menu.getOperation() || 3 == menu.getOperation()) {// 调用服务或跳转链接，那么将消息类型设置为空串
            menu.setType(0);
        }
        if (YYStrKits.isBlank(menu.getId()) || "-1".equals(menu.getId())) {// 增加
            result = add(menu);
            if ("false".equals(result.get("success").toString())) {
                return result;
            }
            String id = (String) result.get("id");
            menusAndMessages(id, msgid);
        } else {// 修改
            result = update(menu);
            if ("false".equals(result.get("success").toString())) {
                return result;
            }
            menusAndMessages(menu.getId(), msgid);
        }
        return result;
    }

    /**
     * <p>
     * 关联菜单与消息
     * </p>
     *
     * @param menuid 菜单id
     * @param msgid  消息id串，以逗号分隔1,2,3
     */
    private void menusAndMessages(String menuid, String msgid) {
        // 增加或修改完关键字以后，关联关键字与消息
        if (YYStrKits.isNotBlank(msgid)) {
            // 先将原来的关联删除掉
            TMenuMessageExample example = new TMenuMessageExample();
            example.createCriteria().andMenu_idEqualTo(menuid);
            tMenuMessageMapper.deleteByExample(example);

            String[] msgids = msgid.split(",");
            for (int i = 0, length = msgids.length; i < length; i++) {
                String mid = msgids[i];
                TMenuMessage km = new TMenuMessage();
                km.setId(YYStrKits.getTableId());
                km.setMessage_id(mid);
                km.setMenu_id(menuid);
                km.setSeq(i + 1);
                tMenuMessageMapper.insert(km);
            }
        }
    }

    /**
     * <p>
     * 菜单键字
     * </p>
     *
     * @param menu 菜单实体
     * @return {@link Map}<String, Object>
     * @author 杨阳
     * @since 2017年9月22日
     */
    private Map<String, Object> update(TMenu menu) {
        Map<String, Object> result = YYMapKits.createHashMap();

        TMenuExample example = new TMenuExample();
        example.createCriteria()
                .andKeycodeEqualTo(menu.getKeycode())
                .andIdEqualTo(menu.getId());

        long accountCount = tMenuMapper.countByExample(example);
        if (accountCount > 0) {
            result.put("success", Boolean.FALSE);
            result.put("msg", "菜单keycode重复，请重试!!");
            return result;
        }

        menu.setUpdate_date(new Date());
        Integer b = tMenuMapper.updateByPrimaryKey(menu);
        if (b > 0) {
            result.put("success", Boolean.TRUE);
            result.put("msg", "修改菜单成功!!");
            result.put("id", menu.getId());
        } else {
            result.put("success", Boolean.FALSE);
            result.put("msg", "修改菜单失败，请重试!!");
        }
        return result;
    }

    /**
     * <p>
     * 判断是否是父节点
     * </p>
     *
     * @param menu {@link Menu}
     * @return {@link Boolean}
     * @author 杨阳
     * @since 2017年9月27日
     */
    private boolean isParentNode(TMenu menu) {
        return "-1".equals(menu.getParentid());
    }

    /**
     * <p>
     * 获得菜单表中已经有多少个父级节点
     * </p>
     *
     * @return {@link Integer} 父节点的个数
     */
    private long getParentNodeCount() {
        TMenuExample example = new TMenuExample();
        example.createCriteria().andParentidEqualTo("-1");
        return tMenuMapper.countByExample(example);
    }

    /**
     * <p>
     * 获得某个菜单已经有多少子节点
     * </p>
     *
     * @param menu {@link Menu}
     * @return {@link Integer} 子节点个数
     */
    private long getChildrenNodeCount(TMenu menu) {
        TMenuExample example = new TMenuExample();
        example.createCriteria().andParentidEqualTo(menu.getParentid());
        return tMenuMapper.countByExample(example);
    }

    /**
     * <p>
     * 增加菜单,
     * 1. 如果是增加父节点，不可以超过4个 2. 如果是增加子节点，每个父节点下不可以超过5个子节点
     * </p>
     *
     * @param menu 菜单实体
     * @return {@link Map}<String, Object>
     * @author 杨阳
     * @since 2017年9月26日
     */
    private Map<String, Object> add(TMenu menu) {
        Map<String, Object> result = YYMapKits.createHashMap();

        String id = YYStrKits.getTableId();
        menu.setId(id);
        // 判断菜单表中的key是否重复
        TMenuExample example = new TMenuExample();
        example.createCriteria().andKeycodeEqualTo(menu.getKeycode());

        long accountCount = tMenuMapper.countByExample(example);
        if (accountCount > 0) {
            result.put("success", Boolean.FALSE);
            result.put("msg", "菜单keycode重复，请重试!!");
            return result;
        }

        // 判断是不是父节点
        boolean isParentNode = isParentNode(menu);
        if (isParentNode) {
            // 获得父节点的个数
            long parentCount = getParentNodeCount();
            if (parentCount > 3) {
                result.put("success", Boolean.FALSE);
                result.put("msg", "只可以添加4个一级菜单!");
                return result;
            }
        } else {
            // 获取子节点个数
            long childCount = getChildrenNodeCount(menu);
            if (childCount > 4) {
                result.put("success", Boolean.FALSE);
                result.put("msg", "一级菜单下可以添加5个二级菜单!");
                return result;
            }
        }

        menu.setCreate_date(new Date());
        Integer b = tMenuMapper.insert(menu);
        if (b > 0) {
            result.put("success", Boolean.TRUE);
            result.put("msg", "增加菜单成功!!");
            result.put("id", id);
        } else {
            result.put("success", Boolean.FALSE);
            result.put("msg", "增加菜单失败，请重试!!");
        }
        return result;
    }

    @Override
    public Map<String, Object> syncToWeChat(String userid) {
        return null;
    }

    @Override
    public Map<String, Object> syncToAlipay(String userid) {
        Map<String, Object> map = YYMapKits.createHashMap();

        // 1.查询菜单表中是否有4个1级菜单，因为支付宝及微信都要求一级菜单只可以有4个
        long levelCount = this.getLevelCount();
        if (levelCount > 4) {
            map.put("success", Boolean.FALSE);
            map.put("msg", "一级菜单数量过多,不可以超过4个!");
            return map;
        }
        // 2.判断一下每一个一级菜单的子节点字数是否合理
        map = this.getTheSubmenuOfThePrimaryMenu();
        if (YYMapKits.isNotEmpty(map)) {// 这里说明有的菜单个数不对，直接返回了
            return map;
        }

        // 3. 将菜单转换为支付宝认识的格式
        map = convertTheMenuToAlipayFormat();
        return map;
    }

    /**
     * <p>
     * 将菜单转换为支付宝认识的格式，以便创建菜单
     * </p>
     *
     * @return {@link Map}<String, Object>
     * @author 杨阳
     * @since 2017年10月9日
     */
    private Map<String, Object> convertTheMenuToAlipayFormat() {

        Map<String, Object> map = YYMapKits.createHashMap();

        JSONObject buttonJson = new JSONObject();
        JSONArray buttonArray = new JSONArray();

        List<TMenu> menuList = getLevelMenu();

        for (int i = 0; i < menuList.size(); i++) {
            TMenu menu = menuList.get(i);

            AlipayMenuDTO menuDto = new AlipayMenuDTO();
            menuDto.setName(menu.getTitle());
            // 设置菜单及型及菜单相关的操作
            menuDto = getAlipayMenuType(menu, menuDto);

            List<AlipayMenuDTO> subButton = YYListKits.createList();

            List<TMenu> twoLevelMenuList = getTwoLevelMenu(menu.getId());
            for (int j = 0; j < twoLevelMenuList.size(); j++) {
                AlipayMenuDTO twoLevelDto = new AlipayMenuDTO();
                // 设置菜单及型及菜单相关的操作
                twoLevelDto = getAlipayMenuType(twoLevelMenuList.get(j), twoLevelDto);
                twoLevelDto.setName(twoLevelMenuList.get(j).getTitle());

                subButton.add(twoLevelDto);
            }
            menuDto.setSub_button(subButton);
            buttonArray.add(menuDto);
        }
        buttonJson.put("button", buttonArray);

        map.put("msg", "同步成功!");
        map.put("success", Boolean.TRUE);

        YYLogKits.error(MenuServiceImpl.class, "转换菜单样式：{}", buttonJson.toString());

        try {
            map = YYAlipayMenuKits.createMenu(buttonJson.toString());
        } catch (AlipayApiException e) {
            map.put("msg", "同步失败,请重试!");
            map.put("success", Boolean.FALSE);
            YYLogKits.error(MenuServiceImpl.class, "转换支付宝菜单异常,{}", e.getMessage());
        }

        return map;
    }

    /**
     * <p>
     * 根据操作类型得设计菜单的类型及菜单相关操作
     * </p>
     *
     * @return {@link AlipayMenuDTO}
     * @author 杨阳
     * @since 2017年10月9日
     */
    private AlipayMenuDTO getAlipayMenuType(TMenu menu, AlipayMenuDTO menuDto) {
        switch (menu.getOperation()) { // 操作类型 1.调用服务 2.发送消息 3.跳转连接 4.无动作
            case 1:// 调用服务
                menuDto.setAction_type("out");
                menuDto.setAction_param(menu.getKeycode());
                break;
            case 2:// 发送消息
                menuDto.setAction_type("out");
                menuDto.setAction_param(menu.getKeycode());
                break;
            case 4:// 无动作
                menuDto.setAction_type("");
                menuDto.setAction_param("");
                break;
            default:// 跳转连接
                menuDto.setAction_type("link");
                menuDto.setAction_param(menu.getLinkaddress());
                break;
        }
        return menuDto;
    }

    /**
     * <p>
     * 获取1级菜单下2级菜单集合
     * </p>
     *
     * @param menuid 一级菜单的id
     * @return {@link List}<Menu>
     * @author 杨阳
     * @since 2017年10月9日
     */
    private List<TMenu> getTwoLevelMenu(String menuid) {
        TMenuExample example = new TMenuExample();
        example.createCriteria()
                .andParentidEqualTo(menuid);
        example.setOrderByClause("seq asc");
        return tMenuMapper.selectByExample(example);
    }

    /**
     * <p>
     * 获得系统中一级菜单
     * </p>
     *
     * @return {@link List}<Menu>
     * @author 杨阳
     * @since 2017年10月9日
     */
    private List<TMenu> getLevelMenu() {
        TMenuExample example = new TMenuExample();
        example.createCriteria()
                .andParentidEqualTo("-1");
        example.setOrderByClause("seq asc");
        return tMenuMapper.selectByExample(example);
    }

    /**
     * <p>
     * 查询出表中一级菜单的数量
     * </p>
     *
     * @return {@link Integer} 一级菜单的数量
     * @author 杨阳
     * @since 2017年10月9日
     */
    private long getLevelCount() {
        TMenuExample example = new TMenuExample();
        example.createCriteria()
                .andParentidEqualTo("-1");
        return tMenuMapper.countByExample(example);
    }

    /**
     * <p>
     * 查询出所有一级菜单，再查询每一个一级菜单下是否最多只有5个子菜单
     * </p>
     *
     * @return {@link Map}
     * @author 杨阳
     * @since 2017年10月9日
     */
    private Map<String, Object> getTheSubmenuOfThePrimaryMenu() {
        Map<String, Object> map = YYMapKits.createHashMap();

        TMenuExample example = new TMenuExample();
        TMenuExample.Criteria criteria = example.createCriteria();
        criteria.andParentidEqualTo("-1");
        List<TMenu> oneList = tMenuMapper.selectByExample(example);

        for (int i = 0; i < oneList.size(); i++) {
            TMenu menu = oneList.get(i);
            String id = menu.getId();
            criteria.andParentidEqualTo(id);
            long clildCount = tMenuMapper.countByExample(example);
            if (clildCount > 5) {
                map.put("success", Boolean.FALSE);
                map.put("msg", "一级菜单[" + menu.getTitle() + "]的子节点数量过多，不可以超过5个!");
                return map;
            } else {
                continue;
            }
        }
        return null;
    }
}
